package br.schindler.android.wallpaper.milkyway;


public class CelestialBody  {
 
	//Eccentricity of orbit
	protected double ec = .20563;

	//Period of orbit (days)
	protected double P = 87.9691;
	 
	//Longitude of asending node 48.331°
	protected double F = (48.331 * Math.PI) / 180;

	//Longitude of perihelion 77.45645°
	protected double  o = (77.45645 * Math.PI) / 180;

	//Angle between plane of sun's equator and plane X'sorbit
	protected double i = (7 * Math.PI) / 180;

	//Semi-major axis km
	protected double a;
	
	// Planet's radius
	private double radius;
	
	// Planet's rotation in days
	protected double r = 58.646;

	// Center
	private CelestialBody center = null;
	
	// Result
	private double R [] = new double [3];
	
	/**
	 * Creates a new planet
	 * @param a 
	 * @param r Planet's radius (unit should be the same as a)
	 */
	public CelestialBody(double a, double r) {	
		this.a = a;
		this.radius = r;
	}

	/**
	 * Creates a new planet
	 * @param a perihelion
	 * @param r Planet's radius (unit should be the same as a)
	 */
	public CelestialBody(CelestialBody center, double a, double r) {	
		this.a = a;
		this.radius = r;
		this.center = center;
	}
	
	/**
	 * Returns local position
	 * @param t
	 * @return [x, y, z]
	 */
	public double [] currentLocation (double t){	
		
		double E    = eccentricAnomaly(t);
		double v    = 2 * Math.atan(Math.sqrt((1+ec)/(1-ec))*Math.tan(E/2));
		double r    = a * (1-ec*ec) / (1 + ec*Math.cos(v));
		
		R[0] = (Math.cos(F)*Math.cos(o+v)-Math.sin(F)*Math.sin(o+v)*Math.cos(i)) * r;
		double y = (Math.sin(F)*Math.cos(o+v)+Math.cos(F)*Math.sin(o+v)*Math.cos(i)) * r;
		double z = (Math.sin(i)*Math.sin(o+v)) * r;
		
		R[1] = Math.cos(i)*y - Math.sin(i)*z;
		R[2] = Math.sin(i)*y + Math.cos(i)*z;
		
		if (null != center){
			double [] cl = center.currentLocation(t);			
			R[0] += cl[0];
			R[1] += cl[1];
			R[2] += cl[2];					
		}
		
		return R;
	}
	
	/**
	 * Planet's radius
	 * @return
	 */
	public double getRadius(){
		return this.radius;
	}
	
	/**
	 * Period of orbit (seconds)
	 * @return period of orbit in seconds
	 */
	public double getOrbitPeriod(){
		return this.P;
	}
	
	/**
	 * Calculates eccentric anomaly is an angular parameter that defines the position 
	 * 	of a body that is moving along an elliptic Kepler orbit.
	 * @param t time in days
	 * @return eccentric anomaly
	 */
	private double eccentricAnomaly(double t){
		double m      = meanAnomaly(t);
		double result = m;	 
		
		for (int i = 0; i < 3; i++){
			result = result - (result - (ec * Math.sin(result)) - m) / (1 - ec * Math.cos(result));
		}
		
		return result;
	}
	
	/**
	 * Calculates mean anomaly is a parameter relating position and time for a body moving in a Kepler orbit. 
	 * It is based on the fact that equal areas are swept in equal intervals of time by a line 
	 * 	joining the focus and the orbiting body (Kepler's second law).
	 * @param t time in days
	 * @return mean anomaly
	 */
	private double meanAnomaly(double t){
		return (2*Math.PI) * (t / (P));
	}	
	
	/**
	 * 
	 * @return
	 */
	public CelestialBody getSatellite(){
		return null;
	}
	
	/**
	 * 
	 * @return
	 */
	public double getRatation() {
		return r;
	}
	
	/**
	 * 
	 * @return
	 */
	public CelestialBody getCenter() {
		return center;
	}

	/**
	 * 
	 * @param center
	 */
	public void setCenter(CelestialBody center) {
		this.center = center;
	}

}